package gen

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"text/template"

	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/util/times"
)

type Porjects struct {
	Projects []Porject `xml:"project"`
}
type Porject struct {
	Name          string `xml:"name"`
	Gen           bool   `xml:"gen"`
	Dir           string `xml:"dir"`
	PackageSepc   string `xml:"packageSepc"`
	DaoPkg        string `xml:"daoPkg"`
	MapperPkg     string `xml:"mapperPkg"`
	ServicePkg    string `xml:"servicePkg"`
	DomainPkg     string `xml:"domainPkg"`
	ControllerPkg string `xml:"controllerPkg"`
}

func ProjectInit(filePath string) Porjects {
	fmt.Println("初始化项目...")
	content, err := ioutil.ReadFile(ConfDir + filePath)
	var config = Porjects{}
	if err != nil {
		fmt.Println("读取项目配置文件出错:", err.Error())
		return config
	}
	err = xml.Unmarshal(content, &config)
	if err != nil {
		fmt.Println("解析数据库配置错误:", err.Error())
		return config
	}
	return config
}

func MkdirAll(filePath string) {
	err := os.MkdirAll(filePath, 0777)
	if err != nil {
		fmt.Println("创建目录失败", err.Error(), filePath)
		panic("创建目录失败")
	} else {
		fmt.Println("创建目录成功", filePath)
	}
}

func PackageDir(module Module, t string) string {
	var project = module.SProject
	var projectDir = project.Dir + "src\\main\\java\\"
	var pkgSepc = strings.Replace(project.PackageSepc, ".", "\\", -1)
	var createPackage = module.CreatePackage
	var dir string
	if t == "domain" {
		dir = fmt.Sprint(projectDir, pkgSepc, "\\", strings.Replace(project.DomainPkg, ".", "\\", -1))
	} else if t == "service" {
		dir = fmt.Sprint(projectDir, pkgSepc, "\\", strings.Replace(project.ServicePkg, ".", "\\", -1))
	} else if t == "dao" {
		dir = fmt.Sprint(projectDir, pkgSepc, "\\", strings.Replace(project.DaoPkg, ".", "\\", -1))
	} else if t == "controller" {
		dir = fmt.Sprint(projectDir, pkgSepc, "\\", strings.Replace(project.ControllerPkg, ".", "\\", -1))
	} else if t == "mapper" {
		dir = fmt.Sprint(projectDir, pkgSepc, "\\", strings.Replace(project.MapperPkg, ".", "\\", -1))
	}
	if createPackage {
		dir = fmt.Sprint(dir, "\\", module.Name)
	}
	return dir
}

func ToUperFirst(s string) string {
	s1 := s[0:1]
	s = strings.ToUpper(s1) + s[1:]
	return s
}

var fieldDbToJava = map[string]string{
	"varchar":  "String",
	"datetime": "java.util.Date",
	"bigint":   "Long",
	"int":      "Integer",
}

func GenGet(s string) string {
	s = "get" + ToUperFirst(Tfname(s))
	return s
}

func GenSet(s string) string {
	s = "set" + ToUperFirst(Tfname(s))
	return s
}

func Tfname(s string) string {
	var str = bytes.Buffer{}
	for i := 0; i < len(s); i++ {
		if s[i] == '_' {
			str.WriteString(strings.ToUpper(s[i+1 : i+2]))
			i++
		} else {
			str.WriteByte(s[i])
		}
	}
	return str.String()
}

type TempData struct {
	Package       string
	BeanPkg       string
	DaoPkg        string
	ServicePkg    string
	ControllerPkg string
	MapperPkg     string
	Bean          string
	Cloums        []ClouMsg
	CeatePkg      bool
	ModuleName    string
}

func NewTempData(tableName string, cloums []ClouMsg, project Porject, module Module) TempData {
	return TempData{
		Package:       project.PackageSepc,
		BeanPkg:       project.DomainPkg,
		DaoPkg:        project.DaoPkg,
		ServicePkg:    project.ServicePkg,
		ControllerPkg: project.ControllerPkg,
		MapperPkg:     project.MapperPkg,
		Bean:          tableName,
		Cloums:        cloums,
		CeatePkg:      module.CreatePackage,
		ModuleName:    module.Name,
	}
}

var (
	filters = template.FuncMap{
		"moduleCrePkg": func(data TempData) string {
			if data.CeatePkg {
				return "." + data.ModuleName
			}
			return ""
		},
		"eqcolms": func(strs ...string) bool {
			var s1 = strs[0]
			var s2s = strs[1:]
			for _, v := range s2s {
				if v == s1 {
					return false
				}
			}
			return true
		},
		"genSet": GenSet,
		"genGet": GenGet,
		"tfname": Tfname,
		"fieldDbToJava": func(s string) string {
			return fieldDbToJava[s]
		},
		"year":     func() string { return times.Format("2006", times.Now()) },
		"blank":    func(s string) bool { return strings.IsBlank(s) },
		"notblank": func(s string) bool { return strings.IsNoneBlank(s) },
		"padright": func(s string, size int) string { return strings.PadRight(s, size, " ") },
		"lower":    func(s string) string { return strings.ToLower(s) },
		"lower1":   func(s string) string { return strings.ToLowerFirst(s) },
		"upper":    func(s string) string { return strings.ToUpper(s) },
		"upper1":   func(s string) string { return strings.ToUpperFirst(s) },
		"camel":    func(s string) string { return strings.Camel(s) },
		"aamel":    func(s string) string { return strings.ToLowerFirst(strings.Camel(s)) },
		"uncamel":  func(s string) string { return strings.UnCamel(s, "_") },
		"tname": func(s string, size int) string { // table name
			v := strings.UnCamel(s, "_")
			v = strings.ToUpper(v)
			return strings.PadRight(v, size+len(v)+1, " ")
		},
		"cname": func(s string, size int) string { // column name
			v := strings.UnCamel(s, "_")
			v = strings.ToUpper(v)
			return strings.PadRight(v, size, " ")
		},
		"fname": func(s string, size int) string { // struct field name
			v := strings.ToUpperFirst(s)
			return strings.PadRight(v, size, " ")
		},
	}
)

func NewTmpl(s string) *template.Template {
	t := template.New("T")
	return template.Must(t.Funcs(filters).Parse(s))
}
